#include "stepping_motor.h"

#include <math.h>
#include <stm32f1xx_hal.h>
#include "tim.h"

#define PWM_TIM     &htim2
#define PWM_CH      TIM_CHANNEL_4

#define PULSE_REV   25000U

#define EN_PORT     STP_MOTOR_EN_GPIO_Port
#define EN_PIN      STP_MOTOR_EN_Pin

#define DIR_PORT    STP_MOTOR_DIR_GPIO_Port
#define DIR_PIN     STP_MOTOR_DIR_Pin

#define POW_PORT    STP_MOTOR_POW_GPIO_Port
#define POW_PIN     STP_MOTOR_POW_Pin

volatile int32_t times = -1;


inline uint32_t INTERNAL_AutoreloadRangeCheck(const uint32_t autoreload) {
    if (autoreload < 100U) return 150U;
    if (autoreload > 10000U) return 10000U;
    return autoreload;
}

void STEPPING_MOTOR_Start(const MOTOR_Direction direction, const uint32_t autoreload) {
    HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, direction);
    HAL_GPIO_WritePin(EN_PORT, EN_PIN, GPIO_PIN_SET);

    HAL_GPIO_WritePin(POW_PORT, POW_PIN, GPIO_PIN_RESET);

    const uint32_t checked_autoreload = INTERNAL_AutoreloadRangeCheck(autoreload);
    __HAL_TIM_SET_AUTORELOAD(PWM_TIM, checked_autoreload - 1);
    __HAL_TIM_SET_COMPARE(PWM_TIM, PWM_CH, checked_autoreload / 2);

    HAL_TIM_PWM_Start_IT(PWM_TIM, PWM_CH);
}

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
    if (htim != PWM_TIM || times == -1) return;
    if (--times == 0) STEPPING_MOTOR_Stop();
}

void STEPPING_MOTOR_TurnAngle(const uint32_t autoreload, const float angle) {
    times = (int32_t)(fabsf(angle) / 360.0f * PULSE_REV);
    STEPPING_MOTOR_Start(angle > 0 ? CLOCKWISE : ANTI_CLOCKWISE, autoreload);
}

void STEPPING_MOTOR_StartSustained(const MOTOR_Direction direction, const uint32_t autoreload, const uint32_t ms) {
    const uint32_t checked_autoreload = INTERNAL_AutoreloadRangeCheck(autoreload);
    times = (int32_t)(ms / checked_autoreload / 1000);
    STEPPING_MOTOR_Start(direction, checked_autoreload);
}

void STEPPING_MOTOR_Stop() {
    HAL_TIM_PWM_Stop_IT(PWM_TIM, PWM_CH);
    HAL_GPIO_WritePin(EN_PORT, EN_PIN, GPIO_PIN_RESET);

    HAL_GPIO_WritePin(POW_PORT, POW_PIN, GPIO_PIN_SET);
}
